package com.developteam.xnmall.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.developteam.xnmall.dao.IndexImgMapper;
import com.developteam.xnmall.entity.IndexImg;
import com.developteam.xnmall.service.IndexImgService;
import com.developteam.xnmall.vo.ResStatus;
import com.developteam.xnmall.vo.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class IndexImgServiceImpl implements IndexImgService {

    @Autowired
    private IndexImgMapper indexImgMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ObjectMapper objectMapper;

    public ResultVO listIndexImgs() {
        List<IndexImg> indexImgs = null;
        try {
            //String imgsStr = stringRedisTemplate.opsForValue().get("indexImgs");
            String imgsStr = stringRedisTemplate.boundValueOps("indexImgs").get();
            if (imgsStr != null) {
                //从redis中获取轮播图信息，转类型
                JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                indexImgs = objectMapper.readValue(imgsStr, javaType);
            } else {
                synchronized (this) {  //锁当前类对象，service类在spring容器中是单例的，所以，1000个并发线程共用一个service实例
                    String s = stringRedisTemplate.boundValueOps("indexImgs").get();
                    if (s == null) {  //只有第一个请求再次查询 redis的时候为 null
//1000个请求同时进到数据库，让它们串行执行，除了第一个请求，剩余的请求都不为空 ———— 缓存击穿
//        stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.DAYS);
                        indexImgs = indexImgMapper.listIndexImgs();    //从redis中没有获取到信息，则查询数据库
                        if (indexImgs != null) {
                            stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(indexImgs), 1, TimeUnit.DAYS);
                        } else {
                            List<IndexImg> arr = new ArrayList<>(); ///写一个非空数据进去 ———— 缓存击穿【双写一致性（两次写操作保证数据强一致性，写数据库的同时写 redis）】
                            stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(arr), 10, TimeUnit.SECONDS);
                        }
                    } else {
                        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                        indexImgs = objectMapper.readValue(s, javaType);
                    }
                }
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //返回数据
        if (indexImgs != null) {
            return new ResultVO(ResStatus.OK, "success", indexImgs);
        } else {
            return new ResultVO(ResStatus.NO, "fail", null);
        }
    }
}
